﻿Imports System.IO


Public Class Emergency_Args
    Inherits EventArgs

    Private m_Progress As Integer = 0
    Private m_Message As String = ""

    Public ReadOnly Property Progress() As Integer
        Get
            Return m_Progress
        End Get
    End Property
    Public ReadOnly Property Message() As String
        Get
            Return m_Message
        End Get
    End Property

    Public Sub New(ByVal percent As Integer, ByVal Message As String)
        m_Progress = percent
        m_Message = Message
    End Sub
End Class

Public Class Program

    Public Event Progress(ByVal sender As Object, ByVal e As Emergency_Args)
    Public Event Message(ByVal sender As Object, ByVal e As Emergency_Args)
    Public m_eeprom() As Byte = Nothing
    Public m_baud As Integer = 500000
    Public m_fuseBit As Byte = 46
    Public m_fuseBitHigh As Byte = 200
    Public m_extended As Byte = 127
    Public m_flash() As Byte = Nothing
    Public m_firmware As Byte() = Nothing
    Private m_progress As Integer = 0
    Private m_save As Boolean = False
    Const rst As Byte = 16
    Private m_BLresponse As Byte
    Private m_message As String = ""
    Private bgw As System.ComponentModel.BackgroundWorker
    Private eventArgs As System.ComponentModel.DoWorkEventArgs
    Private m_device_name As String = ""
    Private m_board_name As String = ""
    Private m_program_firmware As Boolean = True

#Region "---------------= Properties"
    Public WriteOnly Property eeprom() As Byte()
        Set(ByVal value As Byte())
            m_eeprom = value
        End Set
    End Property
    Public WriteOnly Property flash() As Byte()
        Set(ByVal value As Byte())
            m_flash = value
        End Set
    End Property
    Public WriteOnly Property firmware() As Byte()
        Set(ByVal value As Byte())
            m_firmware = value
        End Set
    End Property
#End Region
#Region "---------------= Event Handlers"
    Protected Sub OnProgress(ByVal progress As Integer)
        m_progress = progress
        RaiseEvent Progress(Me, New Emergency_Args(progress, m_message))
    End Sub

    Protected Sub OnMessage(ByVal Message As String)
        m_message = Message
        RaiseEvent Message(Me, New Emergency_Args(m_progress, m_message))
    End Sub
#End Region

    Friend Sub New(ByVal Speed As BK_SPEEDS, Optional ByVal device_name As String = "", Optional ByVal board_name As String = "", Optional ByVal auto_program_fw As Boolean = True)
        m_device_name = device_name
        m_board_name = board_name
        m_program_firmware = auto_program_fw
        Select Case Speed
            Case BK_SPEEDS.BK_16MHz
                m_baud = 500000
                m_fuseBit = 46
                m_fuseBitHigh = 200
                m_extended = 127
                m_BLresponse = &HBB
            Case BK_SPEEDS.BK_12MHz
                m_baud = 375000
                m_fuseBit = 46
                m_fuseBitHigh = 200
                m_extended = 127
                m_BLresponse = &HB9
            Case BK_SPEEDS.BK_8MHz
                m_baud = 250000
                m_fuseBit = 36 ' Internal 8MHz BOD enabled and 00 start up time
                m_fuseBitHigh = 216
                m_extended = 127
                m_BLresponse = &HB1
            Case BK_SPEEDS.BK_8MHz_V3
                m_baud = 250000
                m_BLresponse = &HB3
                m_fuseBit = 98 + 128
                m_extended = 253
                m_fuseBitHigh = 216
            Case BK_SPEEDS.BK_12MHz_V3
                m_fuseBitHigh = 216
                m_fuseBit = 96 + 128
                m_baud = 375000
                m_extended = 253
                m_BLresponse = &HB5
            Case BK_SPEEDS.BK_16MHz_V3
                m_fuseBitHigh = 216
                m_fuseBit = 96 + 128
                m_baud = 500000
                m_extended = 253
                m_BLresponse = &HB5
        End Select
    End Sub
    Friend Sub New(ByVal Speed As BK_SPEEDS, ByVal saveEE As Boolean)
        Me.New(Speed)
        m_save = saveEE
    End Sub

    Public Function Execute( _
             ByVal backGroundWorker As System.ComponentModel.BackgroundWorker, _
             ByVal e As System.ComponentModel.DoWorkEventArgs) As Boolean

        ' Store the reference to the BackgroundWorker and the
        ' DoWorkEventArgs objects:
        bgw = backGroundWorker
        eventArgs = e
        Dim ret As Boolean = True
        Dim f_return As Byte() = Nothing

        ' Program the Bootloader & Atmel variables
        If Not m_flash Is Nothing Then
            ReDim Preserve m_flash(4095)
            If SPI_Connect(, m_device_name) Then
                If spi_reset() Then
                    ' Erase the flash completely
                    chipErase()
                    Threading.Thread.Sleep(4000)
                    If spi_reset() Then
                        Threading.Thread.Sleep(10)
                        SPI_out(172)
                        SPI_out(160)
                        SPI_in()
                        SPI_out(m_fuseBit)
                        Threading.Thread.Sleep(10)
                        SPI_out(172)
                        SPI_out(168)
                        SPI_in()
                        SPI_out(m_fuseBitHigh)
                        Threading.Thread.Sleep(10)
                        SPI_out(172)
                        SPI_out(164)
                        SPI_in()
                        SPI_out(m_extended)
                        Threading.Thread.Sleep(10)
                        SPI_out(172)
                        SPI_out(255)
                        SPI_in()
                        SPI_out(&HFF) ' Unlock device
                        SPI_disconnect()

                        OnMessage("Programming bootloader....")
                        If Not Me.setProgram(m_flash, False, True) Then
                            OnMessage("Bootloader programming failed!")
                            ret = False
                        End If

                        OnMessage("Programming EEprom....")
                        If ret And Not IsNothing(m_eeprom) AndAlso Not Me.setEEprom(m_eeprom) Then
                            OnMessage("Programming EEprom failed!")
                            ret = False
                        End If

                        If ret Then
                            SPI_Connect(, m_device_name)
                            spi_reset()
                            SPI_out(172)
                            SPI_out(255)
                            SPI_in()
                            SPI_out(204) ' Lock device

                            Threading.Thread.Sleep(10)
                            BikiRom_Reset()
                            SPI_disconnect()
                            close_bikirom()
                        End If

                        If ret Then

                            If BikiRom_connect(False, m_board_name) = BK_return.BK_OK Then
                                SetUsbVariable(Biki_USBvars.UV_Baud, m_baud / 1000)
                                close_bikirom()
                            End If

                            If Not IsNothing(bgw) AndAlso bgw.CancellationPending Then
                                eventArgs.Cancel = True
                            End If
                        End If
                    Else
                        ret = False
                        OnMessage("Cannot initialise SPI connection")
                    End If
                Else
                    ret = False
                    OnMessage("Cannot initialise SPI connection")
                End If
            Else
                ret = False
                OnMessage("SPI connection failed!")
            End If
        End If

        ' Program the Firmware via the bootloader
        If Not m_firmware Is Nothing AndAlso ret Then
            'Dim inp As String
            Dim f_errOr As Int16 = 0
            If m_program_firmware Then
retryFirmware:
                OnMessage("Uploading firmware via bootloader....")
                If Not IsNothing(m_firmware) AndAlso Me.program_BootloaderUploadNew(m_board_name) = BK_return.BK_OK Then
                    Try
                        If BikiRom_Init(True, m_board_name) = BK_return.BK_OK Then
                            close_bikirom()

                            OnMessage("Bikirom OS initialisation successful")

                            ret = True
                        Else
                            OnMessage("Unable to initialise Bikirom OS")
                            ret = False
                        End If
                    Catch exUsb As USB_exceptions
                        OnMessage("Unable to initialise Bikirom OS - Unexpected USB fault")
                        ret = False
                    Catch exComm As Comm_Exceptions
                        OnMessage("Unable to initialise Bikirom OS - Intermittend USB communication fault")
                        ret = False
                    End Try

                Else
                    f_errOr += 1
                    If f_errOr >= 2 Then
                        OnMessage("Uploading firmwre failed!")
                        ret = False
                    Else
                        OnMessage("Uploading firmwre failed. retrying....")
                        GoTo retryFirmware
                    End If
                End If
            End If
        End If

        close_bikirom()

        Return ret
    End Function
    Public Sub arrayDump(ByRef sArray() As Byte, ByVal sOutFile As String)
        Dim fStream As New FileStream(sOutFile, FileMode.Create)
        'Dim bWrite As New (fStream)
        fStream.Write(sArray, 0, sArray.Length)
        fStream.Close()
    End Sub
    Public Function setProgram(ByRef a_data() As Byte, ByVal AutoVerify As Boolean, ByVal Program As Boolean) As Boolean
        Dim s_return As Byte
        Dim g, adr As Long
        Dim i As Long
        Dim fnum As Integer = FreeFile()
        Dim spi_enterProgMode As Byte() = {0, rst, 0}
        Dim spi_ProgrammingEnable As Byte() = {172, 83}
        Dim spi_chipErase As Byte() = {172, 128}
        Dim m_error As Integer = 0
        Dim f_genCount As Integer
        Dim f_genCmd(24575) As Byte
        Dim f_return As Integer
        ReDim Preserve a_data(&HFFF)

        If SPI_Connect(, m_device_name) AndAlso spi_reset() Then
            OnMessage("Programing....")
            For i = 126976 To 131071 Step 256
                Console.WriteLine("At the inner loop of " & i, "SPI")
                If Not checkPageEmpty(a_data, i - 126976) Then
                    Console.WriteLine("beyond the Page check " & i, "SPI")
                    If Program = True Then
                        f_genCount = 0
                        ' Generate the programming page
                        For g = i To i + 255 Step 2
restartPageUpload:
                            adr = g \ 2
                            ' Load Program Memory Page Low Byte
                            cmd_add(SPI_out_gen(64), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(0), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(a_data(g - 126976)), f_genCmd, f_genCount)
                            ' Load Program Memory Page High Byte
                            cmd_add(SPI_out_gen(72), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(0), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(a_data(g + 1 - 126976)), f_genCmd, f_genCount)
                        Next
                        ' Load the Program Memory Page
                        FT_Write_Bytes(lngHandle, f_genCmd(0), 24575, f_return)
                        ' Write Program Memory Page
                        SPI_out(76)
                        SPI_out(HIBYTE(adr))
                        SPI_out(LOBYTE(adr))
                        SPI_out(0)
                        Threading.Thread.Sleep(5)
                    End If
                    ' Verify the memory just written
                    If AutoVerify Then
                        Threading.Thread.Sleep(20)
                        For g = i To i + 255 Step 2
                            adr = g \ 2
                            f_genCount = 0
                            cmd_add(SPI_out_gen(&H20), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(HIBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            FT_Write_Bytes(lngHandle, f_genCmd(0), f_genCount, f_return)
                            s_return = SPI_in()

                            If s_return <> a_data(g - 126976) Then
                                Console.WriteLine("Error on Verify")
                                SPI_disconnect()
                                Return False
                            End If

                            f_genCount = 0
                            cmd_add(SPI_out_gen(&H28), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(HIBYTE(adr)), f_genCmd, f_genCount)
                            cmd_add(SPI_out_gen(LOBYTE(adr)), f_genCmd, f_genCount)
                            FT_Write_Bytes(lngHandle, f_genCmd(0), f_genCount, f_return)
                            s_return = SPI_in()

                            If s_return <> a_data(g - 126976 + 1) Then
                                Console.WriteLine("Error on Verify 2")
                                SPI_disconnect()
                                Return False
                            End If
                        Next
                    End If
                    OnProgress(((i - 126976) / 4096) * 100)
                End If
            Next
            Return True
        Else
            Return False
        End If
        OnProgress(100)
        SPI_disconnect()
        Return False
    End Function
    Private Sub cmd_add(ByRef f_from() As Byte, ByRef f_array() As Byte, ByRef f_count As Integer)
        array_copy(f_from, 0, f_array, f_count, f_from.Length)
        f_count += f_from.Length
    End Sub
    Public Function setEEprom(ByRef s_data() As Byte) As Boolean
        Dim i As Long
        Dim bStatus As Boolean = False
        Dim fnum As Integer = FreeFile()
        Dim spi_enterProgMode As Byte() = {0, rst, 0}
        Dim spi_ProgrammingEnable As Byte() = {172, 83}
        Dim f_sndCmd(95) As Byte
        Dim f_cmdCount As Integer
        Dim f_written As Integer

        If Not IsNothing(s_data) AndAlso SPI_Connect(, m_device_name) AndAlso spi_reset() Then
            Console.WriteLine("Communication OK.. programming", "SPI")
            For i = 0 To 143
                Console.WriteLine("At the inner loop of " & i, "SPI")
                If s_data(i) <> 255 Then
                    Console.WriteLine("beyond the Page check " & i, "SPI")
                    f_cmdCount = 0
                    cmd_add(SPI_out_gen(192), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(HIBYTE(i)), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(LOBYTE(i)), f_sndCmd, f_cmdCount)
                    cmd_add(SPI_out_gen(s_data(i)), f_sndCmd, f_cmdCount)
                    FT_Write_Bytes(lngHandle, f_sndCmd(0), 96, f_written)
                    Threading.Thread.Sleep(40)
                End If
                OnProgress((i / 143) * 100)
            Next
            bStatus = True
        End If
        SPI_disconnect()

        Return bStatus
    End Function

    Private Function program_BootloaderUploadNew(Optional ByVal device_name As String = "") As BK_return
        If BikiRom_Init(False, device_name) = BK_return.BK_OK Then
            Dim f_Frame As Comm.Comm_Frame
            Dim f_Packet() As Byte = Nothing
            Dim Address As UInt32 = 0
            Dim Length As UInt32 = 0
            Dim cmd() As Byte = Nothing
            Dim f_data As Byte() = Nothing

            BikiRom_Flush()
            BikiRom_BootMode()

            m_BikiInfo.TimeOut = 20

            Threading.Thread.Sleep(400)

            Try
                f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_BOOTLOADER, , , , Comm.Comm_Frame.BikiFrameType.ID_GENERAL_SPECIFIC)
                f_Frame.Send(f_Packet, False, 50)

                m_BikiInfo.TimeOut = 8000

                If Not IsNothing(f_Packet) Then
                    Select Case (f_Packet(0))
                        Case &H75, &H73, &H71, &H76, &H78, &H79, &H7A
                            f_data = cv_BytesFromHex(m_firmware)
                        Case Else
                            OnMessage("Invalid Bootloader Response")
                            BikiRom_Reset()
                            m_BikiInfo.reset()
                            Return BK_return.BK_FAILED_INIT
                    End Select

                    f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS, , , , Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                    If f_Frame.Send() = Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then

                        While Address < UBound(f_data)
                            Length = (f_data(Address) * &H100) + f_data(Address + 1)

                            ReDim cmd(Length - 3)
                            Array.Copy(f_data, Address + 2, cmd, 0, Length - 2)

                            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_BOOTLOADER, , , cmd, Comm.Comm_Frame.BikiFrameType.ID_LAST_COMMAND_STATUS)
                            f_Frame.Send(, , 4)

                            OnProgress((Address / UBound(f_data)) * 100)

                            Address += Length + 2
                        End While

                    Else
                        OnMessage("Bootloader Erasing Failed")
                        BikiRom_Reset()
                        m_BikiInfo.reset()
                        Return BK_return.BK_FIRMWARE
                    End If

                Else
                    BikiRom_Reset()
                    m_BikiInfo.reset()
                    Return BK_return.BK_FIRMWARE
                End If

                BikiRom_Reset()
                m_BikiInfo.reset()
                Return BK_return.BK_OK

            Catch exComm As Comm_Exceptions
                OnMessage(exComm.Description)
                BikiRom_Reset()
                m_BikiInfo.reset()
                Return BK_return.BK_IO_ERROR_BIK
            Catch exUsb As USB_exceptions
                OnMessage(exUsb.Description)
                BikiRom_Reset()
                m_BikiInfo.reset()
                Return BK_return.BK_IO_ERROR_USB
            End Try
        End If
        close_bikirom()
    End Function

End Class
